home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / libgimp / gimpenv.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-02-13  |  15.3 KB  |  642 lines

  1. /* LIBGIMP - The GIMP Library
  2.  * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
  3.  *
  4.  * gimpenv.c
  5.  *
  6.  * Copyright (C) 1999 Tor Lillqvist
  7.  *
  8.  * This program is free software; you can redistribute it and/or modify
  9.  * it under the terms of the GNU Lesser General Public License as published by
  10.  * the Free Software Foundation; either version 2 of the License, or
  11.  * (at your option) any later version.
  12.  *
  13.  * This program is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  * GNU General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU Lesser General Public License
  19.  * along with this program; if not, write to the Free Software
  20.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21.  */
  22.  
  23. #include "config.h"
  24.  
  25. #include <glib.h>
  26. #include <string.h>
  27. #include <ctype.h>
  28. #include <sys/types.h>
  29. #include <sys/stat.h>
  30. #ifdef HAVE_UNISTD_H
  31. #include <unistd.h>
  32. #endif
  33.  
  34. #include "gimpenv.h"
  35. #include "gimpfeatures.h"
  36.  
  37. #ifdef G_OS_WIN32
  38. #define STRICT
  39. #undef DATADIR            /* typedefed in objidl.h... the value
  40.                    from Makefile not used here anyway */
  41.  
  42. #include <windows.h>        /* For GetModuleFileName */
  43. #include <io.h>
  44. #ifndef S_IWUSR
  45. # define S_IWUSR _S_IWRITE
  46. #endif
  47. #ifndef S_IWGRP
  48. #define S_IWGRP (_S_IWRITE>>3)
  49. #define S_IWOTH (_S_IWRITE>>6)
  50. #endif
  51. #ifndef S_ISDIR
  52. # define __S_ISTYPE(mode, mask)    (((mode) & _S_IFMT) == (mask))
  53. # define S_ISDIR(mode)    __S_ISTYPE((mode), _S_IFDIR)
  54. #endif
  55. #define uid_t gint
  56. #define gid_t gint
  57. #define geteuid() 0
  58. #define getegid() 0
  59. #endif
  60.  
  61. #ifdef __EMX__
  62. extern const char *__XOS2RedirRoot(const char *);
  63. #endif
  64.  
  65. /**
  66.  * gimp_directory:
  67.  *
  68.  * Returns the user-specific GIMP settings directory. If the environment 
  69.  * variable GIMP_DIRECTORY exists, it is used. If it is an absolute path, 
  70.  * it is used as is.  If it is a relative path, it is taken to be a 
  71.  * subdirectory of the home directory. If it is relative path, and no home 
  72.  * directory can be determined, it is taken to be a subdirectory of
  73.  * gimp_data_directory().
  74.  *
  75.  * The usual case is that no GIMP_DIRECTORY environment variable exists, 
  76.  * and then we use the GIMPDIR subdirectory of the home directory. If no 
  77.  * home directory exists, we use a per-user subdirectory of
  78.  * gimp_data_directory().
  79.  * In any case, we always return some non-empty string, whether it
  80.  * corresponds to an existing directory or not.
  81.  *
  82.  * The returned string is allocated just once, and should *NOT* be
  83.  * freed with g_free().
  84.  *
  85.  * Returns: The user-specific GIMP settings directory.
  86.  **/
  87. gchar*
  88. gimp_directory (void)
  89. {
  90.   static gchar *gimp_dir = NULL;
  91.   gchar *env_gimp_dir;
  92.   gchar *home_dir;
  93.   gchar *home_dir_sep;
  94.  
  95.   if (gimp_dir != NULL)
  96.     return gimp_dir;
  97.  
  98.   env_gimp_dir = g_getenv ("GIMP_DIRECTORY");
  99.   home_dir = g_get_home_dir ();
  100.  
  101.   if (home_dir != NULL && home_dir[strlen (home_dir)-1] != G_DIR_SEPARATOR)
  102.     home_dir_sep = G_DIR_SEPARATOR_S;
  103.   else
  104.     home_dir_sep = "";
  105.  
  106.   if (NULL != env_gimp_dir)
  107.     {
  108.       if (g_path_is_absolute (env_gimp_dir))
  109.     gimp_dir = g_strdup (env_gimp_dir);
  110.       else
  111.     {
  112.       if (NULL != home_dir)
  113.         {
  114.           gimp_dir = g_strconcat (home_dir,
  115.                       home_dir_sep,
  116.                       env_gimp_dir,
  117.                       NULL);
  118.         }
  119.       else
  120.         {
  121.           gimp_dir = g_strconcat (gimp_data_directory (),
  122.                       G_DIR_SEPARATOR_S,
  123.                       env_gimp_dir,
  124.                       NULL);
  125.         }
  126.     }
  127.     }
  128.   else
  129.     {
  130. #ifdef __EMX__       
  131.       gimp_dir = g_strdup(__XOS2RedirRoot(GIMPDIR));
  132.       return gimp_dir;  
  133. #endif      
  134.       if (NULL != home_dir)
  135.         {
  136.           gimp_dir = g_strconcat (home_dir,
  137.                                   home_dir_sep,
  138.                                   GIMPDIR,
  139.                                   NULL);
  140.         }
  141.       else
  142.         {
  143.       gchar *user_name = g_strdup (g_get_user_name ());
  144.  
  145. #ifdef G_OS_WIN32
  146.       gchar *p = user_name;
  147.  
  148.       while (*p)
  149.         {
  150.           /* Replace funny characters in the user name with an
  151.            * underscore. The code below also replaces some
  152.            * characters that in fact are legal in file names, but
  153.            * who cares, as long as the definitely illegal ones are
  154.            * caught.
  155.            */
  156.           if (!isalnum (*p) && !strchr ("-.,@=", *p))
  157.         *p = '_';
  158.           p++;
  159.         }
  160. #endif
  161.  
  162. #ifndef G_OS_WIN32
  163.       g_message ("warning: no home directory.");
  164. #endif
  165.  
  166.       gimp_dir = g_strconcat (gimp_data_directory (),
  167.                   G_DIR_SEPARATOR_S,
  168.                   GIMPDIR,
  169.                   ".",
  170.                   user_name,
  171.                   NULL);
  172.       g_free (user_name);
  173.     }
  174.     }
  175.  
  176.   return gimp_dir;
  177. }
  178.  
  179. /**
  180.  * gimp_personal_rc_file:
  181.  * @basename: The basename of a rc_file.
  182.  *
  183.  * Returns the name of a file in the user-specific GIMP settings directory.
  184.  *
  185.  * The returned string is allocated dynamically and *SHOULD* be freed
  186.  * with g_free() after use.
  187.  *
  188.  * Returns: The name of a file in the user-specific GIMP settings directory.
  189.  **/
  190. gchar*
  191. gimp_personal_rc_file (gchar *basename)
  192. {
  193.   return g_strconcat (gimp_directory (),
  194.               G_DIR_SEPARATOR_S,
  195.               basename,
  196.               NULL);
  197. }
  198.  
  199. #ifdef G_OS_WIN32
  200. gchar *
  201. gimp_toplevel_directory ()
  202. {
  203.   /* Figure it out from the executable name */
  204.   static gchar *toplevel = NULL;
  205.   gchar filename[MAX_PATH];
  206.   gchar *sep1, *sep2;
  207.   
  208.   if (toplevel != NULL)
  209.     return toplevel;
  210.   
  211.   if (GetModuleFileName (NULL, filename, sizeof (filename)) == 0)
  212.     g_error ("GetModuleFilename failed\n");
  213.   
  214.   /* If the executable file name is of the format
  215.    * <foobar>\bin\gimp.exe or
  216.    * <foobar>\lib\gimp\GIMP_MAJOR_VERSION.GIMP_MINOR_VERSION\plug-ins\filter.exe,
  217.    * use <foobar>. Otherwise, use the directory where the
  218.    * executable is.
  219.    */
  220.   
  221.   sep1 = strrchr (filename, '\\');
  222.   
  223.   *sep1 = '\0';
  224.   
  225.   sep2 = strrchr (filename, '\\');
  226.   
  227.   if (sep2 != NULL)
  228.     {
  229.       if (g_strcasecmp (sep2 + 1, "bin") == 0)
  230.     {
  231.       *sep2 = '\0';
  232.     }
  233.       else
  234.     {
  235.       gchar test[MAX_PATH];
  236.       
  237.       sprintf (test, "\\lib\\gimp\\%d.%d\\plug-ins",
  238.            GIMP_MAJOR_VERSION, GIMP_MINOR_VERSION);
  239.       
  240.       if (strlen (filename) > strlen (test) &&
  241.           g_strcasecmp (filename + strlen (filename) - strlen (test),
  242.                 test) == 0)
  243.         {
  244.           filename[strlen (filename) - strlen (test)] = '\0';
  245.         }
  246.     }
  247.     }
  248.   toplevel = g_strdup (filename);
  249.   return toplevel;
  250. }
  251. #endif
  252.  
  253. /**
  254.  * gimp_data_directory:
  255.  *
  256.  * Returns the top directory for GIMP data. If the environment variable 
  257.  * GIMP_DATADIR exists, that is used.  It should be an absolute pathname.
  258.  * Otherwise, on Unix the compile-time defined directory is used.  On
  259.  * Win32, the installation directory as deduced from the executable's
  260.  * name is used.
  261.  *
  262.  * The returned string is allocated just once, and should *NOT* be
  263.  * freed with g_free().
  264.  *
  265.  * Returns: The top directory for GIMP data.
  266.  **/
  267. gchar*
  268. gimp_data_directory (void)
  269. {
  270.   static gchar *gimp_data_dir = NULL;
  271.   gchar *env_gimp_data_dir = NULL;
  272.   
  273.   if (gimp_data_dir != NULL)
  274.     return gimp_data_dir;
  275.  
  276.   env_gimp_data_dir = g_getenv ("GIMP_DATADIR");
  277.  
  278.   if (NULL != env_gimp_data_dir)
  279.     {
  280.       if (!g_path_is_absolute (env_gimp_data_dir))
  281.     g_error ("GIMP_DATADIR environment variable should be an absolute path.");
  282. #ifndef __EMX__
  283.       gimp_data_dir = g_strdup (env_gimp_data_dir);
  284. #else      
  285.       gimp_data_dir = g_strdup (__XOS2RedirRoot(env_gimp_data_dir));
  286. #endif      
  287.     }
  288.   else
  289.     {
  290. #ifndef G_OS_WIN32
  291. #ifndef __EMX__
  292.       gimp_data_dir = DATADIR;
  293. #else
  294.       gimp_data_dir = g_strdup(__XOS2RedirRoot(DATADIR));
  295. #endif
  296. #else
  297.       gchar *toplevel = gimp_toplevel_directory ();
  298.       gchar subdir[MAX_PATH];
  299.  
  300.       sprintf (subdir, "share\\gimp\\%d.%d", GIMP_MAJOR_VERSION, GIMP_MINOR_VERSION);
  301.       gimp_data_dir = g_build_filename (toplevel, subdir, NULL);
  302. #endif
  303.     }
  304.   return gimp_data_dir;
  305. }
  306.  
  307. /**
  308.  * gimp_sysconf_directory:
  309.  *
  310.  * Returns the top directory for GIMP config files. If the environment
  311.  * variable GIMP_SYSCONFDIR exists, that is used.  It should be an
  312.  * absolute pathname.  Otherwise, on Unix the compile-time defined
  313.  * directory is used.  On Win32, the installation directory as deduced
  314.  * from the executable's name is used.
  315.  *
  316.  * The returned string is allocated just once, and should *NOT* be
  317.  * freed with g_free().
  318.  *
  319.  * Returns: The top directory for GIMP config files.
  320.  **/
  321. gchar*
  322. gimp_sysconf_directory (void)
  323. {
  324.   static gchar *gimp_sysconf_dir = NULL;
  325.   gchar *env_gimp_sysconf_dir = NULL;
  326.   
  327.   if (gimp_sysconf_dir != NULL)
  328.     return gimp_sysconf_dir;
  329.  
  330.   env_gimp_sysconf_dir = g_getenv ("GIMP_SYSCONFDIR");
  331.  
  332.   if (NULL != env_gimp_sysconf_dir)
  333.     {
  334.       if (!g_path_is_absolute (env_gimp_sysconf_dir))
  335.     g_error ("GIMP_SYSCONFDIR environment variable should be an absolute path.");
  336. #ifndef __EMX__
  337.       gimp_sysconf_dir = g_strdup (env_gimp_sysconf_dir);
  338. #else      
  339.       gimp_sysconf_dir = g_strdup (__XOS2RedirRoot(env_gimp_sysconf_dir));
  340. #endif      
  341.     }
  342.   else
  343.     {
  344. #ifndef G_OS_WIN32
  345. #ifndef __EMX__
  346.       gimp_sysconf_dir = SYSCONFDIR;
  347. #else
  348.       gimp_sysconf_dir = g_strdup(__XOS2RedirRoot(SYSCONFDIR));
  349. #endif
  350. #else
  351.       gchar *toplevel = gimp_toplevel_directory ();
  352.       gchar subdir[MAX_PATH];
  353.  
  354.       sprintf (subdir, "etc\\gimp\\%d.%d", GIMP_MAJOR_VERSION, GIMP_MINOR_VERSION);
  355.       gimp_sysconf_dir = g_build_filename (toplevel, subdir, NULL);
  356. #endif
  357.     }
  358.   return gimp_sysconf_dir;
  359. }
  360.  
  361. /**
  362.  * gimp_gtkrc:
  363.  *
  364.  * Returns the name of the GIMP's application-specific gtkrc file.
  365.  *
  366.  * The returned string is allocated just once, and should *NOT* be
  367.  * freed with g_free().
  368.  *
  369.  * Returns: The name of the GIMP's application-specific gtkrc file.
  370.  **/ 
  371. gchar*
  372. gimp_gtkrc (void)
  373. {
  374.   static gchar *gimp_gtkrc_filename = NULL;
  375.  
  376.   if (gimp_gtkrc_filename != NULL)
  377.     return gimp_gtkrc_filename;
  378.   
  379.  
  380.   gimp_gtkrc_filename = g_strconcat (gimp_sysconf_directory (),
  381.                      G_DIR_SEPARATOR_S,
  382.                      "gtkrc",
  383.                      NULL);
  384.   return gimp_gtkrc_filename;
  385. }
  386.  
  387. /**
  388.  * gimp_path_runtime_fix:
  389.  * @path: A pointer to a string (allocated with g_malloc) that is (or could be) a pathname.
  390.  *
  391.  * On Windows, this function checks if the string pointed to by @path
  392.  * starts with the compile-time prefix, and in that case, replaces the
  393.  * prefix with the run-time one.  @path should be a pointer to a
  394.  * dynamically allocated (with g_malloc, g_strconcat, etc) string. If
  395.  * the replacement takes place, the original string is deallocated,
  396.  * and *@path is replaced with a pointer to a new string with the
  397.  * run-time prefix spliced in.
  398.  */
  399.  
  400. void
  401. gimp_path_runtime_fix (gchar **path)
  402. {
  403. #if defined (G_OS_WIN32) && defined (PREFIX)
  404.   gchar *p;
  405.  
  406.   /* Yes, I do mean forward slashes below */
  407.   if (strncmp (*path, PREFIX "/", strlen (PREFIX "/")) == 0)
  408.     {
  409.       /* This is a compile-time entry. Replace the path with the
  410.        * real one on this machine. */
  411.       p = *path;
  412.       *path = g_strconcat (gimp_toplevel_directory (),
  413.                "\\",
  414.                *path + strlen (PREFIX "/"),
  415.                NULL);
  416.       g_free (p);
  417.     }
  418.   /* Replace forward slashes with backslashes, just for
  419.    * completeness */
  420.   p = *path;
  421.   while ((p = strchr (p, '/')) != NULL)
  422.     {
  423.       *p = '\\';
  424.       p++;
  425.     }
  426. #endif
  427. }
  428.  
  429.  
  430.  
  431. /**
  432.  * gimp_path_parse:
  433.  * @path: A list of directories separated by #G_SEARCHPATH_SEPARATOR.
  434.  * @max_paths: The maximum number of directories to return.
  435.  * @check: #TRUE if you want the directories to be checked.
  436.  * @check_failed: Returns a #GList of path elements for which the
  437.  *                check failed. Each list element is guaranteed
  438.  *          to end with a #G_PATH_SEPARATOR.
  439.  *
  440.  * Returns: A #GList of all directories in @path. Each list element
  441.  *        is guaranteed to end with a #G_PATH_SEPARATOR.
  442.  **/
  443. GList *
  444. gimp_path_parse (gchar     *path,
  445.          gint       max_paths,
  446.          gboolean   check,
  447.          GList    **check_failed)
  448. {
  449.   gchar  *home;
  450.   gchar **patharray;
  451.   GList  *list = NULL;
  452.   GList  *fail_list = NULL;
  453.   gint    i;
  454.  
  455.   struct stat filestat;
  456.   gint        err = FALSE;
  457.  
  458.   if (!path || !*path || max_paths < 1 || max_paths > 256)
  459.     return NULL;
  460.  
  461.   home = g_get_home_dir ();
  462.  
  463.   patharray = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, max_paths);
  464.  
  465.   for (i = 0; i < max_paths; i++)
  466.     {
  467.       GString *dir;
  468.  
  469.       if (!patharray[i])
  470.     break;
  471.  
  472. #ifndef G_OS_WIN32
  473.       if (*patharray[i] == '~')
  474.     {
  475.       dir = g_string_new (home);
  476.       g_string_append (dir, patharray[i] + 1);
  477.     }
  478.       else
  479. #endif
  480.     {
  481.       gimp_path_runtime_fix (&patharray[i]);
  482.       dir = g_string_new (patharray[i]);
  483.     }
  484.  
  485. #ifdef __EMX__
  486.       _fnslashify (dir);
  487. #endif
  488.  
  489.       if (check)
  490.     {
  491.       /*  check if directory exists  */
  492.       err = stat (dir->str, &filestat);
  493.  
  494.       if (!err && S_ISDIR (filestat.st_mode))
  495.         {
  496.           if (dir->str[dir->len - 1] != G_DIR_SEPARATOR)
  497.         g_string_append_c (dir, G_DIR_SEPARATOR);
  498.         }
  499.     }
  500.  
  501.       if (!err)
  502.     list = g_list_prepend (list, g_strdup (dir->str));
  503.       else if (check_failed)
  504.     fail_list = g_list_prepend (fail_list, g_strdup (dir->str));
  505.  
  506.       g_string_free (dir, TRUE);
  507.     }
  508.  
  509.   g_strfreev (patharray);
  510.  
  511.   list = g_list_reverse (list);
  512.  
  513.   if (check && check_failed)
  514.     {
  515.       fail_list = g_list_reverse (fail_list);
  516.       *check_failed = fail_list;
  517.     }
  518.  
  519.   return list;
  520. }
  521.  
  522. /**
  523.  * gimp_path_to_str:
  524.  * @path: A list of directories as returned by gimp_path_parse().
  525.  *
  526.  * Returns: A searchpath string separated by #G_SEARCHPATH_SEPARATOR.
  527.  **/
  528. gchar *
  529. gimp_path_to_str (GList *path)
  530. {
  531.   GString *str = NULL;
  532.   GList   *list;
  533.   gchar   *retval = NULL;
  534.  
  535.   for (list = path; list; list = g_list_next (list))
  536.     {
  537.       if (str)
  538.     {
  539.       g_string_append_c (str, G_SEARCHPATH_SEPARATOR);
  540.       g_string_append (str, (gchar *) list->data);
  541.     }
  542.       else
  543.     {
  544.       str = g_string_new ((gchar *) list->data);
  545.     }
  546.     }
  547.  
  548.   if (str)
  549.     {
  550.       retval = str->str;
  551.       g_string_free (str, FALSE);
  552.     }
  553.  
  554.   return retval;
  555. }
  556.  
  557. /**
  558.  * gimp_path_free:
  559.  * @path: A list of directories as returned by gimp_path_parse().
  560.  *
  561.  * This function frees the memory allocated for the list and it's strings.
  562.  **/
  563. void
  564. gimp_path_free (GList *path)
  565. {
  566.   GList *list;
  567.  
  568.   if (path)
  569.     {
  570.       for (list = path; list; list = g_list_next (list))
  571.     {
  572.       g_free (list->data);
  573.     }
  574.  
  575.       g_list_free (path);
  576.     }
  577. }
  578.  
  579. /**
  580.  * gimp_path_get_user_writable_dir:
  581.  * @path: A list of directories as returned by gimp_path_parse().
  582.  *
  583.  * Note that you have to g_free() the returned string.
  584.  *
  585.  * Returns: The first directory in @path where the user has write permission.
  586.  **/
  587. gchar *
  588. gimp_path_get_user_writable_dir (GList *path)
  589. {
  590.   GList *list;
  591.  
  592.   uid_t euid;
  593.   gid_t egid;
  594.  
  595.   struct stat filestat;
  596.   gint        err;
  597.  
  598.   euid = geteuid ();
  599.   egid = getegid ();
  600.  
  601.   for (list = path; list; list = g_list_next (list))
  602.     {
  603.       /*  check if directory exists  */
  604.  
  605.       /* ugly hack to handle paths with an extra G_DIR_SEPARATOR
  606.        * attached. The stat() in MSVCRT doesn't like that.
  607.        */
  608.       gchar *dir = g_strdup ((gchar *) list->data);
  609.       gchar *p = dir;
  610.       gint pl;
  611.  
  612.       if (g_path_is_absolute (dir))
  613.     p = g_path_skip_root (dir);
  614.       pl = strlen (p);
  615.       if (pl > 0 && p[pl-1] == G_DIR_SEPARATOR)
  616.     p[pl-1] = '\0';
  617.       err = stat (dir, &filestat);
  618.       g_free (dir);
  619.  
  620.       /*  this is tricky:
  621.        *  if a file is e.g. owned by the current user but not user-writable,
  622.        *  the user has no permission to write to the file regardless
  623.        *  of his group's or other's write permissions
  624.        */
  625.       if (!err && S_ISDIR (filestat.st_mode) &&
  626.  
  627.       ((filestat.st_mode & S_IWUSR) ||
  628.  
  629.        ((filestat.st_mode & S_IWGRP) &&
  630.         (euid != filestat.st_uid)) ||
  631.  
  632.        ((filestat.st_mode & S_IWOTH) &&
  633.         (euid != filestat.st_uid) &&
  634.         (egid != filestat.st_gid))))
  635.     {
  636.       return g_strdup ((gchar *) list->data);
  637.     }
  638.     }
  639.  
  640.   return NULL;
  641. }
  642.